package com.zhuangjie.mvc.enhance.mp_query_enhance;

import com.baomidou.mybatisplus.extension.service.IService;
import com.zhaungjie.base.utils.LambdaStructureParser.LambdaStructureParser;
import com.zhaungjie.base.utils.PropertiesCopyUtils.PropertiesCopy;
import com.zhuangjie.mvc.enhance.mp_query_enhance.enums.AggregationOperation;
import com.zhuangjie.mvc.enhance.mp_query_enhance.operation.ForUseOperation;
import com.zhuangjie.mvc.enhance.mp_query_enhance.utils.LambdaGetHashMap;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * LambdaQueryWrapperPlus助手
 *
 * @author zhuangjie
 * @date 2024/05/01
 */
@Component
public class LambdaQueryWrapperPlusHelper {
    private static Map<Class, IService> entityClassMap;
    private static ApplicationContext applicationContext;

    private final static String countAlias = "count";

    public LambdaQueryWrapperPlusHelper(ApplicationContext applicationContext) {
        LambdaQueryWrapperPlusHelper.applicationContext = applicationContext;
        Map<String, IService> beansOfType = applicationContext.getBeansOfType(IService.class);
        if (beansOfType.isEmpty()) return;
        LambdaQueryWrapperPlusHelper.entityClassMap = beansOfType.values().stream().collect(Collectors.toMap(IService::getEntityClass, service -> service));
    }



    @Getter
    @Setter
    @AllArgsConstructor
    @EqualsAndHashCode
    public static class AggregatorMeta {
        private AggregationOperation aggregationOperation;
        private String filedName;
    }


    public static <T> Map<LambdaGetHashMap<Object>, Long> groupCount(LambdaQueryWrapperPlus<T, ?> wrapperPlus) {
        Collection<String> groupByKeys = wrapperPlus.getGroupByKeyMap() == null ? new HashSet<>() : wrapperPlus.getGroupByKeyMap().keySet();
        List<String> selectItems = new ArrayList<>(groupByKeys);
        selectItems.add("count(*) as " + countAlias);
        wrapperPlus.select(selectItems.toArray(new String[0]));
        IService<T> service = findIServiceByEntityClass(wrapperPlus.getEntityClass());
        List<Map<String, Object>> rowList = service.listMaps(wrapperPlus);
        Map<LambdaGetHashMap<Object>, Long> result = new HashMap<>();
        rowList.forEach(row -> {
            LambdaGetHashMap<Object> lambdaGetHashMap = new LambdaGetHashMap<>();
            for (String groupByKey : groupByKeys) {
                lambdaGetHashMap.put(wrapperPlus.getGroupByKeyMap().get(groupByKey), row.get(groupByKey));
            }
            result.put(lambdaGetHashMap, Long.valueOf(String.valueOf(row.get(countAlias))));
        });
        return result;
    }

    public static <E> IService<E> findIServiceByEntityClass(Class<E> entityClass) {
        IService<E> iService = entityClassMap.get(entityClass);
        if (iService == null) {
            // 尝试再次从容器中获取
            for (IService<E> service : applicationContext.getBeansOfType(IService.class).values()) {
                if (service.getEntityClass().equals(entityClass)) {
                    entityClassMap.put(entityClass, service);
                    return service;
                }
            }
        }
        return iService;
    }

    /**
     *查询多条
     * @param wrapperPlus
     * @param fun mybatisPlus的查询方法如list方法引用
     * @return
     */
    public static <E, R> List<R> queryList(LambdaQueryWrapperPlus<E, R> wrapperPlus, Function<LambdaQueryWrapperPlus<E, R>, List<E>> fun) {
        Class<R> rClass = wrapperPlus.getRClass();
        if (rClass == null) {
            throw new RuntimeException("LambdaQueryWrapperPlusHelper.queryList：LambdaQueryWrapperPlus写法有误，导致无法确定RClass");
        }
        List<E> entities = fun.apply(wrapperPlus);
        Class<E> entityClass = wrapperPlus.getEntityClass();
        return PropertiesCopy.type(entityClass, rClass)
                .batchProduce(entities);
    }

    public static <E, R> List<R> queryList(LambdaQueryWrapperPlus<E, R> wrapperPlus) {
        IService<E> service = findIServiceByEntityClass(wrapperPlus.getEntityClass());
        if (service == null) {
            throw new RuntimeException("LambdaQueryWrapperPlusHelper.queryList未找到对应的IService");
        }
        return queryList(wrapperPlus, service::list);
    }


    public static <E, R> R queryOne(LambdaQueryWrapperPlus<E, R> wrapperPlus, Function<LambdaQueryWrapperPlus<E, R>, E> fun) {
        Class<R> rClass = wrapperPlus.getRClass();
        if (rClass == null) {
            throw new RuntimeException("LambdaQueryWrapperPlusHelper.queryOne：LambdaQueryWrapperPlus写法有误，导致无法确定RClass!");
        }
        E entities = fun.apply(wrapperPlus);
        Class<E> entityClass = wrapperPlus.getEntityClass();
        return PropertiesCopy.type(entityClass, rClass)
                .produce(entities);
    }

    /**
     * 只查询列信息
     * @param wrapperPlus
     * @param fun
     * @return
     * @param <E>
     * @param <R>
     * @param <RT>
     */
    public static<E,R,RT> List<RT> queryColumn(LambdaQueryWrapperPlus<E, R> wrapperPlus, LambdaStructureParser.NAHRFunction<E,RT> fun) {
        IService<E> service = findIServiceByEntityClass(wrapperPlus.getEntityClass());
        String SelectColumnFieldName = LambdaStructureParser.convertToFieldName(fun);
        wrapperPlus.selectForFieldName(SelectColumnFieldName);
        List<Map<String, Object>> maps = service.listMaps(wrapperPlus);
        return maps.stream().map(map -> {
            Object o = map.get(SelectColumnFieldName);
            return o == null?null:(RT)o;
        }).filter(Objects::nonNull).collect(Collectors.toList());
    }


    public static <E, R> R queryOne(LambdaQueryWrapperPlus<E, R> wrapperPlus, IService<E> service) {
        return queryOne(wrapperPlus, service::getOne);
    }

    public static <E, R> R queryOne(LambdaQueryWrapperPlus<E, R> wrapperPlus) {
        IService<E> service = findIServiceByEntityClass(wrapperPlus.getEntityClass());
        if (service == null) {
            throw new RuntimeException("LambdaQueryWrapperPlusHelper.queryOne未找到对应的IService");
        }
        return queryOne(wrapperPlus, service::getOne);
    }
    /**
     * groupBy的forUse
     *
     * @param wrapperPlus 包装+
     * @param injectClass 注入类
     * @return {@link ForUseOperation }<{@link E }, {@link R },{@link IT }>
     */
    public static <E, R,IT> ForUseOperation<E, R,IT> forGroupUse(LambdaQueryWrapperPlus<E, R> wrapperPlus,Class<IT> injectClass) {
        return new ForUseOperation<>(wrapperPlus);
    }

    /**
     * 简单表查询的forUse
     * @param wrapperPlus
     * @return
     * @param <E>
     * @param <R>
     */
    public static <E, R> ForUseOperation<E, R,Object> forUse(LambdaQueryWrapperPlus<E, R> wrapperPlus) {
        return new ForUseOperation<>(wrapperPlus);
    }

    /**
     * 看是否存在满足条件的记录
     *
     * @param wrapperPlus 包装+
     * @return boolean
     */
    public static<E> boolean exists(LambdaQueryWrapperPlus<E, ?> wrapperPlus) {
        LambdaQueryWrapperPlus<E, ?> instanceWrapperPlus = wrapperPlus.instance();
        instanceWrapperPlus.limit(1);
        IService<E> service = findIServiceByEntityClass(wrapperPlus.getEntityClass());
        return service.count(wrapperPlus) > 0;
    }




}
